home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 January: Mac OS SDK / Dev.CD Jan 99 SDK2.toast / Development Kits / QuickTake Digital Camera / MyQuickTakeApp 1.0.2 ƒ / Sources / Floating Windows (8⁄94 JW) / WindowExtensions.c
Encoding:
C/C++ Source or Header  |  1995-05-26  |  28.2 KB  |  982 lines  |  [TEXT/MMCC]

  1. /*
  2.     File:        WindowExtensions.c
  3.     
  4.     Contains:    Routines to support floating windows
  5.     
  6.     Written by:    Dean Yu
  7.     
  8.     Copyright:    © 1993 Apple Computer, Inc.
  9.     
  10. */
  11.  
  12. #include <Types.h>
  13. #include <Events.h>
  14. #include <Memory.h>
  15. #include <Menus.h>
  16. #include <Processes.h>
  17. #include <Resources.h>
  18. #include <LowMem.h>        // dkj replaced SysEqu.h
  19. #include <ToolUtils.h>
  20. #include <Windows.h>
  21.  
  22. #include "WindowExtensions.h"
  23.  
  24. // Internal routine prototypes
  25.  
  26. static void ActivateWindow(WindowExt theWindow);
  27. static void DeactivateWindow(WindowExt theWindow);
  28. static void HighlightAndActivateWindow(WindowExt theWindow, Boolean activate);
  29. static WindowExt GetWindowList(void);
  30. static void SetWindowList(WindowExt windowReference);
  31.  
  32. //
  33. // NewWindowReference
  34. //
  35. //    Create a new window, and return a reference to it.
  36. //
  37.  
  38. pascal OSErr NewWindowReference(WindowExt *windowReference, const Rect *boundsRect,
  39.  ConstStr255Param title, Boolean visible, WindowAttributes attributes, WindowExt behind,
  40.  long refCon, ActivateHandlerUPP activateHandlerProc)
  41. {
  42.     WindowAttributes    titleBarType;
  43.     WindowExt            newWindowReference;
  44.     WindowExt            lastFloater;
  45.     long                gestaltResult;
  46.     OSErr                result = noErr;
  47.     OSErr                gestaltError;
  48.     short                procID;
  49.     Boolean                hasGoAway = false;
  50.     
  51.     // Determine the type of title bar this window has, if any.
  52.     
  53.     titleBarType = attributes & kWindowTitlebarMask;
  54.     if (titleBarType != 0) {
  55.         switch (titleBarType) {
  56.             case kHasRoundedTitlebarMask:
  57.             case kHasDocumentTitlebarMask:    if ((behind == (WindowExt) -1) &&
  58.                                                 ((lastFloater = LastFloatingWindow()) != nil))
  59.                                                 behind = lastFloater;
  60.                                             
  61.                                             if (titleBarType == kHasRoundedTitlebarMask)
  62.                                                 procID = kRoundedWindowProc;
  63.                                             else
  64.                                                 procID = kStandardDocumentWindowProc;
  65.                                             break;
  66.             case kHasPaletteTitlebarMask:    if (((behind == nil) && (FrontNonFloatingWindow() != nil)) ||
  67.                                                 ((behind != (WindowExt) -1) && (GetWindowKind(behind) != kApplicationFloaterKind))) {
  68.                                                 *windowReference = 0;
  69.                                                 return kInvalidWindowOrderingError;
  70.                                             }
  71.                                             procID = kFloatingWindowProc;
  72.                                             break;
  73.             default:                        procID = kStandardDocumentWindowProc;
  74.                                             result = kUndefinedTitleBarTypeError;
  75.                                             break;
  76.         }
  77.         
  78.         // This window has a title bar.  See what kind of gadgets it has in it.
  79.     
  80.         if (attributes & kHasModalBorderMask)        // Moveable modals don’t get zoom, close, or grow boxes
  81.             procID += movableDBoxProc;
  82.         else {
  83.             if (attributes & kHasCloseBoxMask)
  84.                 hasGoAway = true;
  85.             if (attributes & kHasZoomBoxMask)
  86.                 procID += zoomDocProc;
  87.             if (!(attributes & kHasGrowBoxMask))
  88.                 procID += noGrowDocProc;
  89.         }
  90.     }
  91.     
  92.     // This window has no title bar, so it’s a dialog of some sort.
  93.     // We’re going to be dictatorial and say that these types of windows
  94.     // can only come up in front.
  95.     
  96.     else {
  97.         if (behind != (WindowExt) -1) {
  98.             *windowReference = 0;
  99.             return kInvalidWindowOrderingError;
  100.         }
  101.         
  102.         procID = dBoxProc;                                // Start with the standard dialog type
  103.         if (!(attributes & kHasModalBorderMask)) {
  104.             procID = plainDBox;                            // This isn’t the standard modal type
  105.             if (attributes & kHasThickDropShadowMask)    // These types can have a deeper drop shadow
  106.                 procID = altDBoxProc;
  107.         }
  108.     }
  109.     
  110.     newWindowReference = (WindowExt) NewPtr(sizeof(WindowRecordExtensions));
  111.     
  112.     if (MemError() == noErr) {
  113.  
  114.     // Call the real Window Manager routine to create the window:
  115.     // If Color Quickdraw is available, always create a color window.  If Color Quickdraw
  116.     // is not around, or Gestalt spewed, create a classic window.
  117.     
  118.         gestaltError = Gestalt(gestaltQuickdrawVersion, &gestaltResult);
  119.         if ((gestaltError != noErr) || (gestaltResult == gestaltOriginalQD))
  120.             NewWindow(newWindowReference, boundsRect, title, false, procID, (WindowRef) behind,
  121.                 hasGoAway, refCon);
  122.         else
  123.             NewCWindow(newWindowReference, boundsRect, title, false, procID, (WindowRef) behind,
  124.                 hasGoAway, refCon);
  125.         
  126.     // If a window was successfully created, set its activate event handler proc and show
  127.     // it if the caller wanted a visible window.
  128.     
  129.         *windowReference = newWindowReference;        // Return a reference to the window
  130.         SetActivateHandlerProc(newWindowReference, activateHandlerProc);
  131.         
  132.         if (attributes & kHasPaletteTitlebarMask)    // Set the windowKind for floating windows
  133.             SetWindowKind(newWindowReference, kApplicationFloaterKind);
  134.             
  135.         if (visible)                                // Show the window
  136.             ShowReferencedWindow(newWindowReference);
  137.     }
  138.     else {
  139.         *windowReference = 0;
  140.         result = kWindowNotCreatedError;
  141.     }
  142.         
  143.     return result;
  144. }
  145.  
  146. //
  147. // GetNewWindowReference
  148. //
  149. //    Create a window based on information in the specified resource.
  150. //
  151.  
  152. pascal OSErr GetNewWindowReference(WindowExt *windowReference, short windResourceID,
  153.  WindowExt behind, ActivateHandlerUPP activateHandler)
  154. {
  155.     WindowExt    newWindowReference;
  156.     WindowExt    lastFloatingWindow;
  157.     WindowExt    windowReferenceStorage;
  158.     long        gestaltResult;
  159.     OSErr        gestaltError;
  160.     OSErr        result;
  161.     short        defProcID;
  162.     
  163.     result = noErr;
  164.     windowReferenceStorage = (WindowExt) NewPtr(sizeof(WindowRecordExtensions));
  165.     
  166.     if (MemError() == noErr) {
  167.  
  168.     // Create a window based on the specified 'WIND' resource.  If Color Quickdraw
  169.     // is around, create a color window, otherwise, make a black and white one.
  170.     
  171.         gestaltError = Gestalt(gestaltQuickdrawVersion, &gestaltResult);
  172.         if ((gestaltError != noErr) || (gestaltResult == gestaltOriginalQD))
  173.             newWindowReference = (WindowExt) GetNewWindow(windResourceID, windowReferenceStorage, (WindowRef) behind);
  174.         else
  175.             newWindowReference = (WindowExt) GetNewCWindow(windResourceID, windowReferenceStorage, (WindowRef) behind);
  176.     
  177.     // If we got a window, create the reference, then make sure the windowKind field is
  178.     // set correctly for floating windows.
  179.     
  180.         if (newWindowReference != nil) {
  181.             *windowReference = newWindowReference;
  182.             SetActivateHandlerProc(newWindowReference, activateHandler);
  183.             
  184.     // Figure out if this is a floating window, based upon the resource ID of the 'WDEF'.
  185.     // This is a really wierd way of doing it, but this allows the 'WIND' resource to
  186.     // describe the floatability of a window.
  187.     //
  188.     // A little known fact about GetResInfo is that if you specify nil for any of the
  189.     // info parameters, then it won’t return that information.  Handy, huh?
  190.     
  191.             GetResInfo(GetWindowDefProc(newWindowReference), &defProcID, nil, nil);
  192.             
  193.             if (defProcID == rFloatingWindowProc) {
  194.             
  195.     // Return an error if it’s a floating window being created behind a non floating window.
  196.             
  197.                 if (((behind == nil) && (FrontNonFloatingWindow() != nil)) ||
  198.                     ((behind != (WindowExt) -1) && (GetWindowKind(behind) != kApplicationFloaterKind))) {
  199.                     *windowReference = 0;
  200.                     return kInvalidWindowOrderingError;
  201.                 }
  202.                 else {
  203.                     SetWindowKind(newWindowReference, kApplicationFloaterKind);
  204.                     HiliteWindow((WindowRef) newWindowReference, true);
  205.                 }
  206.             }
  207.             else
  208.             
  209.     // If we’re not creating a floating window, but the application wanted it in the
  210.     // front, create the window behind the last floating window.
  211.             
  212.                 if (behind == (WindowExt) -1) {
  213.                     lastFloatingWindow = LastFloatingWindow();
  214.                     
  215.                     if (lastFloatingWindow != nil)
  216.                         SendBehind((WindowRef) newWindowReference, (WindowRef) lastFloatingWindow);
  217.                     else
  218.                         BringToFront((WindowRef) newWindowReference);
  219.                 }
  220.         }
  221.         else {
  222.             DisposePtr((Ptr) windowReferenceStorage);
  223.             *windowReference = 0;
  224.             result = kWindowNotCreatedError;
  225.         }
  226.     }
  227.     else {
  228.         *windowReference = 0;
  229.         result = kWindowNotCreatedError;
  230.     }
  231.     
  232.     return result;
  233. }
  234.  
  235. //
  236. // DisposeWindowReference
  237. //
  238. //    Free the memory used by a window.  If it is visible, hide it first so
  239. //    that the proper activate and deactivate events are sent.
  240. //
  241.  
  242. pascal void DisposeWindowReference(WindowExt windowReference)
  243. {
  244.     if (IsWindowVisible(windowReference))
  245.         HideReferencedWindow(windowReference);
  246.     CloseWindow((WindowRef) windowReference);
  247.     DisposePtr((Ptr) windowReference);
  248. }
  249.  
  250. //
  251. // SelectedReferencedWindow
  252. //
  253. // Select the specified window, and bring it to the front if its portion
  254. // of the window list.
  255. //
  256.  
  257. pascal void SelectReferencedWindow(WindowExt windowToSelect)
  258. {
  259.     WindowExt            currentFrontWindow;
  260.     WindowExt            lastFloatingWindow;
  261.     Boolean                isFloatingWindow;
  262.  
  263.     if (GetWindowKind(windowToSelect) == kApplicationFloaterKind) {
  264.         isFloatingWindow = true;
  265.         currentFrontWindow = (WindowExt) FrontWindow();
  266.     }
  267.     else {
  268.         isFloatingWindow = false;
  269.         currentFrontWindow = FrontNonFloatingWindow();
  270.         lastFloatingWindow = LastFloatingWindow();
  271.     }
  272.  
  273.     // Be fast (and lazy) and do nothing if we don’t have to.
  274.  
  275.     if (currentFrontWindow != windowToSelect) {
  276.  
  277.     // Selecting floating windows are easy, since they’re always active
  278.  
  279.         if (isFloatingWindow)
  280.             BringToFront((WindowRef) windowToSelect);
  281.         else {
  282.     
  283.     // If there are no floating windows, we can call SelectWindow like the good ol’ days
  284.  
  285.             if (lastFloatingWindow == nil)
  286.                 SelectWindow((WindowRef) windowToSelect);
  287.             else {
  288.  
  289.     // Deactivate the window currently in front.
  290.                 
  291.                 DeactivateWindow(currentFrontWindow);
  292.     
  293.     // Bring it behind the last floating window and activate it.
  294.     // Note that Inside Mac 1 states that you need to call PaintOne() and CalcVis() on a
  295.     // window if you are using SendBehind() to bring it closer to the front.  With System 7,
  296.     // this is no longer necessary.
  297.  
  298.                 SendBehind((WindowRef) windowToSelect, (WindowRef) lastFloatingWindow);
  299.                 ActivateWindow(windowToSelect);
  300.             }
  301.         }
  302.     }
  303. }
  304.  
  305. //
  306. // ShowReferencedWindow
  307. //
  308. //    Show the specified window.  If the window is the frontmost document window,
  309. //    unhighlight the window behind it, deactivate it, and activate this one.
  310. //
  311.  
  312. pascal void ShowReferencedWindow(WindowExt windowToShow)
  313. {
  314.     WindowExt            windowBehind;
  315.     WindowExt            frontNonFloatingWindow;
  316.     ActivateHandlerUPP    activateHandlerProc;
  317.     short                windowClass;
  318.     Boolean                windowIsInFront = false;
  319.     
  320.     if (IsWindowVisible(windowToShow) != false)
  321.         return;
  322.         
  323.     windowClass = GetWindowKind(windowToShow);
  324.     
  325.     // If the window behind the window to show is currently the frontmost document window,
  326.     // unhighlight it, and highlight the new front window.
  327.     
  328.     if (windowClass != kApplicationFloaterKind) {
  329.         windowBehind = (WindowExt) (WindowExt) GetNextWindow(windowToShow);
  330.         if (windowBehind == FrontNonFloatingWindow()) {
  331.             if (windowBehind != nil)
  332.                 DeactivateWindow(windowBehind);
  333.  
  334.     // Set the highlight state so the window appears highlighted from the start.
  335.     
  336.             SetWindowHilite(windowToShow, true);
  337.             windowIsInFront = true;
  338.         }
  339.     }
  340.     else {
  341.     
  342.     // A floating window is about to be shown. Make sure the windows in the window list
  343.     // are all in the right place.
  344.     
  345.         ValidateWindowList();
  346.         
  347.     // Check to see if a modal window is up before trying to highlight it.
  348.     
  349.         frontNonFloatingWindow = FrontNonFloatingWindow();
  350.         if ((frontNonFloatingWindow != nil) &&
  351.             (frontNonFloatingWindow == (WindowExt) FrontWindow()) &&
  352.             (WindowIsModal(frontNonFloatingWindow)))
  353.             SetWindowHilite(windowToShow, false);
  354.         else {
  355.             SetWindowHilite(windowToShow, true);
  356.             windowIsInFront = true;
  357.         }
  358.     }
  359.     
  360.     // Show the window
  361.     
  362.     ShowHide((WindowRef) windowToShow, true);
  363.     
  364.     // If this is the new frontmost document window or a floating window, send it an activate event
  365.     
  366.     if (windowIsInFront) {
  367.         activateHandlerProc = GetActivateHandlerProc(windowToShow);
  368.         if (activateHandlerProc != nil)
  369.             CallActivateHandlerProc(activateHandlerProc, windowToShow, kActivateWindow);
  370.     }
  371. }
  372.  
  373. //
  374. // HideReferencedWindow
  375. //
  376. //    Hide the specified window.  If it is frontmost, move it behind the window immediately
  377. //    behind it, like HideWindow does.
  378. //
  379.  
  380. pascal void HideReferencedWindow(WindowExt windowToHide)
  381. {
  382.     WindowExt            frontFloater;
  383.     WindowExt            frontNonFloater;
  384.     WindowExt            lastFloater;
  385.     WindowExt            windowBehind;
  386.     
  387.     // Don’t do anything if the window is already invisible.
  388.     
  389.     if (IsWindowVisible(windowToHide) == false)
  390.         return;
  391.     
  392.     // Get the first visible floating window, if any.
  393.     
  394.     frontFloater = (WindowExt) FrontWindow();
  395.     if (GetWindowKind(frontFloater) != kApplicationFloaterKind)
  396.         frontFloater = nil;
  397.         
  398.     // Get the first visible document window, if any.
  399.     
  400.     frontNonFloater = FrontNonFloatingWindow();
  401.     
  402.     // Hide the window.
  403.     
  404.     ShowHide((WindowRef) windowToHide, false);
  405.     
  406.     // If the frontmost floating window is being hidden, move it behind the floating window
  407.     // behind it, if there is one.
  408.     
  409.     if (windowToHide == frontFloater) {
  410.         windowBehind = (WindowExt) GetNextWindow(windowToHide);
  411.         
  412.     // Only do the rearrangement if there’s another floating window.
  413.     
  414.         if ((windowBehind != nil) &&
  415.             (GetWindowKind(windowBehind) == kApplicationFloaterKind)) {
  416.             SetNextWindow(windowToHide, (WindowExt) GetNextWindow(windowBehind));
  417.             SetNextWindow(windowBehind, windowToHide);
  418.             SetWindowList(windowBehind);
  419.         }
  420.     }
  421.     else {
  422.     
  423.     // If the frontmost document window is behind hidden, send it behind the window
  424.     // behind it.
  425.     
  426.         if (windowToHide == frontNonFloater) {
  427.             windowBehind = (WindowExt) GetNextWindow(windowToHide);
  428.             
  429.             if (windowBehind != nil) {
  430.                 SetNextWindow(windowToHide, (WindowExt) GetNextWindow(windowBehind));
  431.                 SetNextWindow(windowBehind, windowToHide);
  432.                 
  433.     // Set the next link of the last floating window to point to the previously second
  434.     // to front document window. If there was no floating window, change the beginning
  435.     // of the window list.
  436.     
  437.                 lastFloater = LastFloatingWindow();
  438.                 if (lastFloater != nil)
  439.                     SetNextWindow(lastFloater, windowBehind);
  440.                 else
  441.                     SetWindowList(windowBehind);
  442.                 
  443.     // The window behind it is now the front document window.  Highlight it and send it
  444.     // and activate event.
  445.                 
  446.                 ActivateWindow(windowBehind);
  447.             }
  448.         }
  449.     }
  450. }
  451.  
  452. pascal void DragReferencedWindow(WindowExt windowToDrag, Point startPoint, const Rect *draggingBounds)
  453. {
  454.     Rect        dragRect;
  455.     KeyMap        keyMap;
  456.     GrafPtr        savePort;
  457.     GrafPtr        windowManagerPort;
  458.     RgnHandle    dragRegion;
  459.     RgnHandle    windowContentRegion;
  460.     long        dragResult;
  461.     short        topLimit;
  462.     short        newHorizontalWindowPosition;
  463.     short        newVerticalWindowPosition;
  464.     short        horizontalOffset;
  465.     short        verticalOffset;
  466.     Boolean        commandKeyDown = false;
  467.     
  468.     if (WaitMouseUp()) {
  469.     
  470.     // Adjust the top of the dragging rectangle so that it’s below the menu bar
  471.     
  472.         topLimit = GetMBarHeight() + 4;
  473.         dragRect = *draggingBounds;
  474.         if (dragRect.top < topLimit)
  475.             dragRect.top = topLimit;
  476.     
  477.     // Set up the Window Manager port.
  478.     
  479.         GetPort(&savePort);
  480.         GetWMgrPort(&windowManagerPort);
  481.         SetPort(windowManagerPort);
  482.         SetClip(GetGrayRgn());
  483.         
  484.     // Check to see if the command key is down.  If it is, don’t bring the window to the
  485.     // front after the move.  Trying to do Pascal stuff in C is so much fun.  GetKeys()
  486.     // is a total pain to try to use properly from C, so I’m going to hard code where the
  487.     // command key is in the KeyMap array.
  488.     
  489.         GetKeys(keyMap);
  490.         if (keyMap[1] & 0x8000)
  491.             commandKeyDown = true;
  492.     
  493.         if ((commandKeyDown == true) ||
  494.             (GetWindowKind(windowToDrag) != kApplicationFloaterKind)) {
  495.             
  496.             if (commandKeyDown == false)
  497.     
  498.     // If there are floating windows, clip the dragging outline to draw behind the floaters.
  499.     
  500.                 ClipAbove((WindowRef) FrontNonFloatingWindow());
  501.             else
  502.             
  503.     // If the command key was down, clip the outline to draw behind any windows above
  504.     // the window being dragged.
  505.     
  506.                 ClipAbove((WindowRef) windowToDrag);
  507.         }
  508.             
  509.     // Create a region to drag
  510.     
  511.         dragRegion = NewRgn();
  512.         CopyRgn(GetStructureRegion(windowToDrag), dragRegion);
  513.         
  514.     // Drag the window around
  515.     
  516.         dragResult = DragGrayRgn(dragRegion, startPoint, &dragRect, &dragRect, noConstraint, nil);
  517.     
  518.     // Restore the port for coordinate conversion.
  519.     
  520.         SetPort(savePort);
  521.  
  522.         if (dragResult != 0) {
  523.             horizontalOffset = dragResult & 0xFFFF;
  524.             verticalOffset = dragResult >> 16;
  525.     
  526.     // Only move it if it stayed inside the dragging box.
  527.     
  528.             if (verticalOffset != -32768) {
  529.                 windowContentRegion = GetContentRegion(windowToDrag);
  530.                 newHorizontalWindowPosition = (**windowContentRegion).rgnBBox.left + horizontalOffset;
  531.                 newVerticalWindowPosition = (**windowContentRegion).rgnBBox.top + verticalOffset;
  532.                 
  533.                 MoveWindow((WindowRef) windowToDrag, newHorizontalWindowPosition, newVerticalWindowPosition, false);
  534.                 
  535.             }
  536.         }
  537.     
  538.     // Bring the window forward if the command key wasn’t down
  539.     
  540.         if (commandKeyDown == false)
  541.             SelectReferencedWindow(windowToDrag);
  542.     
  543.     // Get rid of the dragging region
  544.     
  545.         DisposeRgn(dragRegion);
  546.     }
  547. }
  548.  
  549. //
  550. // FrontNonFloatingWindow
  551. //
  552. //    Return the first visible window that is not a floating window.
  553. //
  554.  
  555. pascal WindowExt FrontNonFloatingWindow(void)
  556. {
  557.     WindowExt    theWindow;
  558.     
  559.     // Get the first visible window in the window list.
  560.     
  561.     theWindow = (WindowExt) FrontWindow();
  562.     
  563.     // Keep searching until a visible window whose windowKind is not
  564.     // kApplicationFloaterKind is found, or the end of the window list is reached.
  565.     
  566.     while ((theWindow != nil) && (GetWindowKind(theWindow) == kApplicationFloaterKind)) {
  567.         do {
  568.             theWindow = (WindowExt) GetNextWindow(theWindow);
  569.         } while ((theWindow != nil) && (IsWindowVisible(theWindow) == false));
  570.     }
  571.  
  572.     return theWindow;
  573. }
  574.  
  575. //
  576. // LastFloatingWindow
  577. //
  578. //    Return the last floating window, whether it is visible or not, or nil if there are
  579. //    no floating windows.
  580. //
  581.  
  582. pascal WindowExt LastFloatingWindow(void)
  583. {
  584.     WindowExt    theWindow;
  585.     WindowExt    lastFloatingWindow;
  586.     
  587.     theWindow = GetWindowList();
  588.     lastFloatingWindow = nil;
  589.     
  590.     // We have to search the entire window list because we don’t know what the windowKind
  591.     // of other windows in the list might be, and we have account for the fact that a modal
  592.     // dialog is up.
  593.     
  594.     while (theWindow != nil) {
  595.         if (GetWindowKind(theWindow) == kApplicationFloaterKind)
  596.             lastFloatingWindow = theWindow;
  597.         theWindow = (WindowExt) GetNextWindow(theWindow);
  598.     }
  599.     
  600.     return lastFloatingWindow;
  601. }
  602.  
  603. //
  604. // WindowIsModal
  605. //
  606. //    Determines if a window is modal based upon the value of its windowKind and window variant.
  607. //
  608.  
  609. pascal Boolean WindowIsModal(WindowExt windowReference)
  610. {
  611.     short    windowVariant;
  612.     
  613.     windowVariant = GetWVariant((WindowRef) windowReference);
  614.     if ((GetWindowKind(windowReference) == dialogKind) &&
  615.         ((windowVariant == dBoxProc) ||
  616.         (windowVariant == movableDBoxProc)))
  617.         return true;
  618.     else
  619.         return false;
  620. }
  621.  
  622. //
  623. // DeactivateFloatersAndFirstDocumentWindow
  624. //
  625. //    Send deactivate events to all visible floating windows and the active document
  626. //    window.  This routine is called before a modal dialog is presented.
  627. //
  628.  
  629. pascal void DeactivateFloatersAndFirstDocumentWindow(void)
  630. {
  631.     WindowExt            firstWindow;
  632.     WindowExt            secondDocumentWindow;
  633.     WindowExt            currentWindow;
  634.     
  635.     // First, make sure the window ordering hasn’t been changed behind our back
  636.     ValidateWindowList();
  637.     
  638.     // Start from the frontmost window on the screen, and keep going until
  639.     // we’ve reached the second document window.
  640.     
  641.     firstWindow = (WindowExt) FrontWindow();
  642.     secondDocumentWindow = FrontNonFloatingWindow();
  643.     if (secondDocumentWindow != nil)
  644.         secondDocumentWindow = (WindowExt) GetNextWindow(secondDocumentWindow);
  645.         
  646.     currentWindow = firstWindow;
  647.     while (currentWindow != secondDocumentWindow) {
  648.         if (IsWindowVisible(currentWindow))
  649.             DeactivateWindow(currentWindow);
  650.         currentWindow = (WindowExt) GetNextWindow(currentWindow);
  651.     }
  652. }
  653.  
  654. //
  655. // ActivateFloatersAndFirstDocumentWindow
  656. //
  657. //    ActivateFloatersAndFirstDocumentWindow should be called after a modal dialog
  658. //    is dismissed.  If the application is in the background when this routine is
  659. //    called (like when a moveable modal progress dialog was up and then disappears)
  660. //    this routine calls SuspendFloatingWindows to hide any visible floating windows
  661. //    instead.
  662. //
  663.  
  664. pascal void ActivateFloatersAndFirstDocumentWindow(void)
  665. {
  666.     ProcessSerialNumber    currentPSN;
  667.     ProcessSerialNumber    frontPSN;
  668.     WindowExt            firstWindow;
  669.     WindowExt            secondDocumentWindow;
  670.     WindowExt            currentWindow;
  671.     OSErr                getFrontProcessResult;
  672.     OSErr                getCurrentProcessResult;
  673.     OSErr                sameProcessResult;
  674.     Boolean                isSameProcess;
  675.     
  676.     // See if the this process is in the background.  If it is, then the floating
  677.     // windows should be hidden instead of reactivated, so SuspendFloatingWindows()
  678.     // is called instead.
  679.     
  680.     getFrontProcessResult = GetFrontProcess(&frontPSN);
  681.     getCurrentProcessResult = GetCurrentProcess(¤tPSN);
  682.     
  683.     if ((getFrontProcessResult == noErr) && (getCurrentProcessResult == noErr))
  684.         sameProcessResult = SameProcess(&frontPSN, ¤tPSN, &isSameProcess);
  685.         
  686.     if ((sameProcessResult == noErr) && (isSameProcess == false))
  687.         SuspendFloatingWindows();
  688.     else {
  689.         firstWindow = (WindowExt) FrontWindow();
  690.         secondDocumentWindow = FrontNonFloatingWindow();
  691.         if (secondDocumentWindow != nil)
  692.             secondDocumentWindow = (WindowExt) GetNextWindow(secondDocumentWindow);
  693.         
  694.         currentWindow = firstWindow;
  695.         while (currentWindow != secondDocumentWindow) {
  696.             if (IsWindowVisible(currentWindow))
  697.                 ActivateWindow(currentWindow);
  698.             currentWindow = (WindowExt) GetNextWindow(currentWindow);
  699.         }
  700.     }
  701. }
  702.  
  703. //
  704. // SuspendFloatingWindows
  705. //
  706. //    Hide any visible floating windows, and deactivate the frontmost document window.
  707. //    This routine should be called when an application recieves a suspend event.
  708. //
  709.  
  710. pascal void SuspendFloatingWindows(void)
  711. {
  712.     WindowExt    currentWindow;
  713.     Boolean        windowIsVisible;
  714.     
  715.     currentWindow = (WindowExt) GetWindowList();
  716.     if (GetWindowKind(currentWindow) != kApplicationFloaterKind)
  717.         return;
  718.         
  719.     do {
  720.         windowIsVisible = IsWindowVisible(currentWindow);
  721.         SetWasVisible(currentWindow, windowIsVisible);
  722.         if (windowIsVisible)
  723.             ShowHide((WindowRef) currentWindow, false);
  724.         currentWindow = (WindowExt) GetNextWindow(currentWindow);
  725.     } while ((currentWindow != nil) &&
  726.              (GetWindowKind(currentWindow) == kApplicationFloaterKind));
  727.     
  728.     // The floating windows are now hidden.  Deactivate the first visible
  729.     // document window.
  730.     
  731.     currentWindow = FrontNonFloatingWindow();
  732.     if (currentWindow != nil)
  733.         DeactivateWindow(currentWindow);
  734. }
  735.  
  736. //
  737. // ResumeFloatingWindows
  738. //
  739. //    Reveal floating windows that were hidden by SuspendFloatingWindows.  An
  740. //    activate event is sent to each one as it is revealed.  The frontmost document
  741. //    is also sent an activate event.
  742. //
  743.  
  744. pascal void ResumeFloatingWindows(void)
  745. {
  746.     WindowExt    currentWindow;
  747.     Boolean        windowWasVisible;
  748.     
  749.     currentWindow = GetWindowList();
  750.     if (GetWindowKind(currentWindow) != kApplicationFloaterKind)
  751.         return;
  752.         
  753.     do {
  754.         windowWasVisible = GetWasVisible(currentWindow);
  755.         if (windowWasVisible) {
  756.             ShowHide((WindowRef) currentWindow, true);
  757.             ActivateWindow(currentWindow);
  758.         }
  759.         currentWindow = (WindowExt) GetNextWindow(currentWindow);
  760.     } while ((currentWindow != nil) &&
  761.              (GetWindowKind(currentWindow) == kApplicationFloaterKind));
  762.  
  763.     // The floating windows have been revealed.  Activate the first document
  764.     // window as well.
  765.     
  766.     currentWindow = FrontNonFloatingWindow();
  767.     if (currentWindow != nil)
  768.         ActivateWindow(currentWindow);
  769. }
  770.  
  771. //
  772. // ActivateWindow
  773. //
  774. //    Activates the window by highlighting it, and calling its activate handler.
  775. //
  776.  
  777. void ActivateWindow(WindowExt theWindow)
  778. {
  779.     HighlightAndActivateWindow(theWindow, kActivateWindow);
  780. }
  781.  
  782. //
  783. // DeactivateWindow
  784. //
  785. //    Deactivates the window by unhighlighting it and calling its activate handler.
  786. //
  787.  
  788. void DeactivateWindow(WindowExt theWindow)
  789. {
  790.     HighlightAndActivateWindow(theWindow, kDeactivateWindow);
  791. }
  792.  
  793. //
  794. // HighlightAndActivateWindow
  795. //
  796. //    Common code for ActivateWindow and DeactivateWindow.  Does actual highlighting
  797. //    and calling of the activate handler.
  798. //
  799.  
  800. void HighlightAndActivateWindow(WindowExt theWindow, Boolean activate)
  801. {
  802.     ActivateHandlerUPP    activateHandlerProc;
  803.     
  804.     activateHandlerProc = GetActivateHandlerProc(theWindow);
  805.     HiliteWindow((WindowRef) theWindow, activate);
  806.     if (activateHandlerProc != nil)
  807.         CallActivateHandlerProc(activateHandlerProc, theWindow, activate);
  808. }
  809.  
  810. //
  811. // ValidateWindowList
  812. //
  813. //    Code external to the application might call SelectWindow or FrontWindow because they
  814. //    don’t know any better. If the application has floating windows that are invisible
  815. //    when some other code calls FrontWindow then SelectWindow, a document window will get
  816. //    pulled in front of the invisible floating windows. This routine makes sure everything
  817. //    is right with the world, or at least the window list. It assumes that the floating
  818. //    windows are invisible, so visually, nothing changes on the screen. This means that
  819. //    the code doesn’t call CalcVBehind or PaintBehind. If I wanted to be more general,
  820. //    those two calls would have to be made. Ideally, this routine only needs to be called
  821. //    the first time window ordering changes after a foreign window was opened in your
  822. //    applicaiton. I’m actually calling it every time ShowReferencedWindow is called on
  823. //    a floating window, and when new document windows are created or closed, just to be
  824. //    safe.
  825. //
  826.  
  827. pascal void ValidateWindowList(void)
  828. {
  829.     WindowExt    currentWindow = GetWindowList();
  830.     WindowExt    lastFloatingWindow = LastFloatingWindow();
  831.     WindowExt    firstFloatingWindow = nil;
  832.     WindowExt    documentWindowsToMove = nil;
  833.     WindowExt    lastDocumentWindowAdded = nil;
  834.     WindowExt    previousWindow = nil;
  835.     
  836.     if (currentWindow) {
  837.     
  838.     // First, gather up all the document windows in front of floating windows. We iterate
  839.     // through the window list until a floating window is encountered.
  840.     
  841.         do {
  842.             if (GetWindowKind(currentWindow) == kApplicationFloaterKind) {
  843.                 firstFloatingWindow = currentWindow;
  844.                 break;
  845.             }
  846.             else {
  847.                 SetNextWindow(previousWindow, (WindowExt) GetNextWindow(currentWindow));
  848.  
  849.                 if (documentWindowsToMove == nil)
  850.                     documentWindowsToMove = currentWindow;
  851.                 else
  852.                     SetNextWindow(lastDocumentWindowAdded, currentWindow);
  853.                 lastDocumentWindowAdded = currentWindow;
  854.                 
  855.                 previousWindow = currentWindow;
  856.                 currentWindow = (WindowExt) GetNextWindow(currentWindow);
  857.             }
  858.         } while (currentWindow);
  859.         
  860.     // Now put them back in their place.
  861.     
  862.         if (documentWindowsToMove && firstFloatingWindow) {
  863.             SetNextWindow(lastDocumentWindowAdded, (WindowExt) GetNextWindow(lastFloatingWindow));
  864.             SetNextWindow(lastFloatingWindow, documentWindowsToMove);
  865.             
  866.     // If the first window in the window list was a document window, and there are
  867.     // floating windows, then make the floating window the first window in the window
  868.     // list.
  869.             if (documentWindowsToMove == GetWindowList())
  870.                 SetWindowList(firstFloatingWindow);
  871.         }
  872.     }
  873. }
  874.  
  875. //
  876. // Getters and Setters
  877. //
  878.  
  879. //    GetWindowPortRect — returns the portRect from the window’s GrafPort.
  880.  
  881. pascal void GetWindowPortRect(WindowExt windowReference, Rect *portRect)
  882. {
  883.     *portRect = ((WindowRef) windowReference)->portRect;
  884. }
  885.  
  886.  
  887. // SetWindowVisible — get and set the visible field for a window
  888.  
  889. pascal void SetWindowVisible(WindowExt windowReference, Boolean windowVisible)
  890. {
  891.     windowReference->theWindow.visible = windowVisible;
  892. }
  893.  
  894.  
  895. // SetWindowHilite — get and set the hilited field of a window
  896.  
  897. pascal void SetWindowHilite(WindowExt windowReference, Boolean windowHilite)
  898. {
  899.     windowReference->theWindow.hilited = windowHilite;
  900. }
  901.  
  902.  
  903. // Get/SetNextWindow — get and set the window after this window
  904.  
  905. pascal void SetNextWindow(WindowExt windowReference, WindowExt nextWindow)
  906. {
  907.     windowReference->theWindow.nextWindow = (WindowPeek) nextWindow;
  908. }
  909.  
  910.  
  911. // GetContentRegion — return the window’s content region
  912.  
  913. pascal RgnHandle GetContentRegion(WindowExt windowReference)
  914. {
  915.     return (windowReference->theWindow.contRgn);
  916. }
  917.  
  918.  
  919. // GetStructureRegion — return the window’s structure region
  920.  
  921. pascal RgnHandle GetStructureRegion(WindowExt windowReference)
  922. {
  923.     return (windowReference->theWindow.strucRgn);
  924. }
  925.  
  926.  
  927. // GetWindowDefPRoc - return a handle to the window’s definition procedure
  928.  
  929. pascal Handle GetWindowDefProc(WindowExt windowReference)
  930. {
  931.     return (windowReference->theWindow.windowDefProc);
  932. }
  933.  
  934.  
  935. // Get/SetActivateHandlerProc — get and set the activate event handler for this window
  936.  
  937. pascal ActivateHandlerUPP GetActivateHandlerProc(WindowExt windowReference)
  938. {
  939.     return (windowReference->activateHandlerProc);
  940. }
  941.  
  942. pascal void SetActivateHandlerProc(WindowExt windowReference, ActivateHandlerUPP activateHandlerProc)
  943. {
  944.     windowReference->activateHandlerProc = activateHandlerProc;
  945. }
  946.  
  947.  
  948. // Get/SetWasVisible — save and restore the visible field of a window
  949.  
  950. pascal Boolean GetWasVisible(WindowExt windowReference)
  951. {
  952.     return (windowReference->wasVisible);
  953. }
  954.  
  955. pascal void SetWasVisible(WindowExt windowReference, Boolean wasVisible)
  956. {
  957.     windowReference->wasVisible = wasVisible;
  958. }
  959.  
  960.  
  961. // GetWindowList — Return the first window in the application’s window list from low memory.
  962. // dkj Changed these routines to use LMGet and LMSet
  963.  
  964. WindowExt GetWindowList(void)
  965. {
  966.     return ((WindowExt) LMGetWindowList());
  967. }
  968.  
  969. // SetWindowList — Set the first window in this process’ window list.
  970.  
  971. void SetWindowList(WindowExt windowReference)
  972. {
  973.     LMSetWindowList((WindowRef) windowReference);
  974. }
  975.  
  976. //    Routine added by John Wang
  977.  
  978. extern pascal WindowRef WindowRefFromExt(WindowExt windowReference)
  979. {
  980.     return ( (WindowRef) windowReference);
  981. }
  982.